#include "file_op.h"
// #include <openssl/sha.h>
#include <openssl/evp.h>
#include "progress_bar.h"

//  int recvFile(int socket_fb,char* fileName){
//  //接口参数信息
//     int netfb=socket_fb;
//     //文件固定目录
//     char file_real_download_path[2048]={0};//改为固定的目录
//     mkdir("./download", 0755);
//     strcat(file_real_download_path,"./download");
//     //==========================================
//     //能否下载该文件
//     train_t train;
//     memset(&train,0,sizeof(train));
//     recv(netfb,&train.length,sizeof(train.length),MSG_WAITALL);
//         recv(netfb,train.value,train.length,MSG_WAITALL);
//     if(strcmp(train.value,"0")==0){
//         printf("无该文件，不可下载\n");
//     }else{
//         printf("有该文件，开始下载\n");
//         off_t filesize=0;
//         memset(&train,0,sizeof(train));
//         /* recv(netfb,&train.length,sizeof(train.length),MSG_WAITALL); */
//         /* printf("train.length=%d\n",train.length); */
//         recv(netfb,&filesize,sizeof(filesize),MSG_WAITALL);//接收文件
//         printf("filesize==%ld\n",filesize);
//         bzero(train.value,sizeof(train.value));
//         //========================================================
//         //获得将要下载的文件的hash值
//         recv(netfb,&train.length,sizeof(train.length),MSG_WAITALL);
//         bzero(train.value,sizeof(train.value));
//         recv(netfb,train.value,train.length,MSG_WAITALL);
//         char recv_hash[1024]={0};
//         strcat(recv_hash,train.value);
//         printf("recv_hash is:%s\n",recv_hash);
//         //============================================================
//         char file_real_hash_path[2048]={0};
//         strcat(file_real_hash_path,file_real_download_path);
//         strcat(file_real_hash_path,"/");
//         // strcat(file_real_hash_path,recv_hash);
//         strcat(file_real_hash_path,fileName);
//         printf("file_real_hash_path:%s\n",file_real_hash_path);
//         int file_fb=open(file_real_hash_path,O_RDWR|O_CREAT,0777);//打开真实文件
//         ERROR_CHECK(file_fb,-1,"open");
//         bzero(&train,sizeof(train));
//         //==============================================================
//         char *suffix="_temp.txt";
//         char temp_filename[200]={0};
//         strcat(temp_filename,recv_hash);//拼接hash值
//         strcat(temp_filename,suffix);
//         char temp_file_name_path[2048]={0};
//         strcat(temp_file_name_path,file_real_download_path);
//         strcat(temp_file_name_path,"/");
//         strcat(temp_file_name_path,temp_filename);
//         strcat(temp_file_name_path,suffix);//拼接临时文件路径
//         int temp_file_fd=open(temp_file_name_path,O_RDWR|O_CREAT,0666);
//         ERROR_CHECK(temp_file_fd,-1,"open temp_file");
//         int temp_file_lseek_ret=lseek(temp_file_fd,0,SEEK_SET);//将临时文件的指针指向开始位置
//         printf("temp_file_lseek_ret=%d\n",temp_file_lseek_ret);
//         off_t size=0;
//         off_t current_filesize=0;
//         while(1){//每次一个off_t的大小进行读取临时文件
//             int ret=read(temp_file_fd,&size,sizeof(off_t));
//             if(0==ret){
//                 printf("read temp_file over\n");
//                 break;
//             }
//             current_filesize+=size;
//         } 
//         send(netfb,&current_filesize,sizeof(current_filesize),MSG_NOSIGNAL);
//         printf("current_filesize==%ld\n",current_filesize);
//         //======================================================================  
//         if(current_filesize==filesize){
//             printf("该文件已存在,通知发送方不再发送，极速秒传，仅校验hash值\n");
//             char flag[]="1";
//             train.length=sizeof(flag);//发送标志位，让客户端不再发送
//             strcpy(train.value,flag);
//             send(netfb,&train.length,sizeof(train.length),0);
//             send(netfb,train.value,train.length,0);
//             //=================================================
//             goto sha256_Hash;//goto sha1_Hash:校验现有文件hash值
//         }else if(0<=current_filesize){
//             char flag[]="0";
//             train.length=sizeof(flag);//发送标志位，让服务端发送
//             strcpy(train.value,flag);
//             send(netfb,&train.length,sizeof(train.length),0);
//             send(netfb,train.value,train.length,0);
//         }
//         //========================================================================
//         int lseek_ret=lseek(file_fb,current_filesize,SEEK_SET);//设置文件指向,指到文件末尾
//         printf("lseek_ret==%d\n",lseek_ret);
//         //======================================================================
// reload:
//         if(filesize<100*1024*1024){
//             off_t total=0;
//             while(1){
//                 printf("%5.2lf%%\r",100.0*total/filesize);
//                 fflush(stdout);
//                 recv(netfb,&train.length,sizeof(train.length),MSG_WAITALL);
//                 if(total==filesize){
//                     printf("recv over\n");
//                     break;
//                 }
//                 total+=train.length;
//                 recv(netfb,train.value,train.length,MSG_WAITALL);//如果是最后的车头为0的时，接收会阻塞吗                                                                                                          
//                 write(file_fb,train.value,train.length);
//                 off_t one_size=train.length;
//                 write(temp_file_fd,&one_size,sizeof(off_t));//向临时文件写入每次传入的字节数
//                 bzero(train.value,train.length);
//             }
//             printf("100.00%%\n");
//         }else{
//             char recv_data[1024 * 1024] = {0};
//             int ftruncate_add_ret = ftruncate(file_fb, filesize);
//             printf("ftruncate_add_ret=%d\n", ftruncate_add_ret);

//             long page_size = sysconf(_SC_PAGESIZE); // 获取系统页大小（通常 4KB）
//             while (current_filesize < filesize) {
//                 off_t ret = recv(netfb, recv_data, sizeof(recv_data), 0);
//                 if (ret == 0) {
//                     printf("发送方中断\n");
//                     break;
//                 }
//                 // 计算对齐后的 offset（向下取整到页边界）
//                 off_t aligned_offset = (current_filesize / page_size) * page_size;
//                 // 计算映射后指针需要偏移的量（current_filesize - aligned_offset）
//                 size_t ptr_offset = current_filesize - aligned_offset;
//                 //要接收的剩余文件大小
//                 size_t remaining=filesize - aligned_offset;
//                 char *mapped = mmap(NULL, remaining, PROT_READ | PROT_WRITE, MAP_SHARED, file_fb, aligned_offset);
//                 if (mapped == MAP_FAILED) {
//                     perror("mmap");
//                     close(file_fb);
//                     return -1;
//                 }

//                 // 调整指针，使其指向接收中断位置
//                 char *effective_ptr = mapped + ptr_offset;
//                 memcpy(effective_ptr, recv_data, ret);
//                 /* int w_ret= */
//                 write(temp_file_fd,&ret,sizeof(ret));//向临时文件写入每次传入的字节数
//                 /* printf("ret=%ld, w_ret=%d\n",ret,w_ret); */
//                 // 清理映射
//                 munmap(mapped, remaining);
//                 current_filesize += ret;
//             }
//             printf("接收完毕\n");
//             ftruncate(file_fb, current_filesize);
//         }
// // sha1_Hash:  
// //         //判断文件是否损坏
// //         //计算hash值
// //         SHA_CTX ctx;
// //         SHA1_Init(&ctx);
// //         char buf[4096];
// //         /* int fb=open(,O_RDWR); */
// //         /* printf("fb==%d\n",fb); */
// //         while(1){
// //             bzero(buf,sizeof(buf));
// //             ssize_t ret=read(file_fb,buf,sizeof(buf));
// //             if(ret==0){
// //                 printf("read over\n");
// //                 break;
// //             }
// //             SHA1_Update(&ctx,buf,ret);
// //         }
// //         unsigned char HASH_SHA[SHA_DIGEST_LENGTH];
// //         SHA1_Final(HASH_SHA,&ctx);
// //         char sha1str[SHA_DIGEST_LENGTH * 2 + 1]={0};
// //         printf("file hash:");
// //         for(int i=0;i<sizeof(HASH_SHA);i++){
// //             char temp[3]={0};                                                               
// //             sprintf(temp,"%02x",HASH_SHA[i]);
// //             strcat(sha1str,temp);
// //         }
// //         printf("sha1str=%s\n",sha1str);

// //         if(strcmp(sha1str,recv_hash)==0){
// //             printf("校验hash相同\n");
// //             train.length=sizeof("0");
// //             strcpy(train.value,"0");
// //             send(netfb,&train.length,sizeof(train.length),0);
// //             send(netfb,train.value,train.length,0);
// //         }else{
// //             printf("校验hash不同\n");
// //             train.length=sizeof("1");
// //             strcpy(train.value,"1");
// //             send(netfb,&train.length,sizeof(train.length),0);
// //             send(netfb,train.value,train.length,0);
// //             lseek(file_fb,0,SEEK_SET);//设置文件指向,指到文件开始
// //             current_filesize=0;
// //             printf("请求重新接收文件\n");
// //             goto reload;
// //         }

// sha256_Hash:  
//         //判断文件是否损坏
//         //计算hash值
//         EVP_MD_CTX *ctx = EVP_MD_CTX_new();
//         EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
//         char buf[4096];
//         /* int fb=open(,O_RDWR); */
//         /* printf("fb==%d\n",fb); */
//         while(1){
//             bzero(buf,sizeof(buf));
//             ssize_t ret=read(file_fb,buf,sizeof(buf));
//             if(ret==0){
//                 printf("read over\n");
//                 break;
//             }
//             EVP_DigestUpdate(ctx, buf, ret);
//         }
//         unsigned char HASH_SHA[32];
//         unsigned int encrypted_len = 0;
//         EVP_DigestFinal_ex(ctx, HASH_SHA, &encrypted_len);
//         char sha256str[65]={0};
//         printf("file hash:");
//         for (int i = 0; i < encrypted_len; i++)
//         {
//             sprintf(sha256str + i * 2, "%02x", HASH_SHA[i]);
//         }
//         sha256str[64] = '\0';
//         printf("sha256str=%s\n",sha256str);

//         if(strcmp(sha256str,recv_hash)==0){
//             printf("校验hash相同\n");
//             train.length=sizeof("0");
//             strcpy(train.value,"0");
//             send(netfb,&train.length,sizeof(train.length),0);
//             send(netfb,train.value,train.length,0);
//         }else{
//             printf("校验hash不同\n");
//             train.length=sizeof("1");
//             strcpy(train.value,"1");
//             send(netfb,&train.length,sizeof(train.length),0);
//             send(netfb,train.value,train.length,0);
//             lseek(file_fb,0,SEEK_SET);//设置文件指向,指到文件开始
//             current_filesize=0;
//             printf("请求重新接收文件\n");
//             goto reload;
//         }
//        printf("recive file success\n");
//     }
//     return 0;
// }

int recvFile(int socket_fb,char* fileName, int log_fd){
 //接口参数信息
    int netfb=socket_fb;
    //文件固定目录
    char file_real_download_path[2048]={0};//改为固定的目录
    mkdir("./download", 0755);
    strcat(file_real_download_path,"./download");
    //==========================================
    //能否下载该文件
    train_t train;
    memset(&train,0,sizeof(train));
    recv(netfb,&train.length,sizeof(train.length),MSG_WAITALL);
        recv(netfb,train.value,train.length,MSG_WAITALL);
    if(strcmp(train.value,"0")==0){
        printf("无该文件，不可下载\n");
    }else{
        printf("有该文件，开始下载\n");
        off_t filesize=0;
        memset(&train,0,sizeof(train));
        recv(netfb,&filesize,sizeof(filesize),MSG_WAITALL);//接收文件
        printf("filesize==%ld\n",filesize);
        bzero(train.value,sizeof(train.value));
        //========================================================
        //获得将要下载的文件的hash值
        recv(netfb,&train.length,sizeof(train.length),MSG_WAITALL);
        bzero(train.value,sizeof(train.value));
        recv(netfb,train.value,train.length,MSG_WAITALL);
        char recv_hash[1024]={0};
        strcat(recv_hash,train.value);
        printf("recv_hash is:%s\n",recv_hash);
        //============================================================
        char file_real_hash_path[2048]={0};
        strcat(file_real_hash_path,file_real_download_path);
        strcat(file_real_hash_path,"/");
        // strcat(file_real_hash_path,recv_hash);
        strcat(file_real_hash_path,fileName);
        printf("file_real_hash_path:%s\n",file_real_hash_path);
        int file_fb=open(file_real_hash_path,O_RDWR|O_CREAT,0666);//打开真实文件
        // ERROR_CHECK(file_fb,-1,"open");
        if(file_fb == -1)
        {
            LOG_INFO(log_fd, LOG_ERROR, "open %s failed.",file_real_hash_path);
            return -1;
        }
        bzero(&train,sizeof(train));
        //==============================================================
        char *suffix="_temp.txt";
        char temp_filename[200]={0};
        strcat(temp_filename,recv_hash);//拼接hash值
        strcat(temp_filename,suffix);
        char temp_file_name_path[2048]={0};
        strcat(temp_file_name_path,file_real_download_path);
        strcat(temp_file_name_path,"/");
        strcat(temp_file_name_path,temp_filename);
        int temp_file_fd=open(temp_file_name_path,O_RDWR|O_CREAT,0666);
        printf("temp_file_fd==%d\n",temp_file_fd);
        printf("temp_file_name_path==%s\n",temp_file_name_path);
        // off_t size=0;
        off_t current_filesize=0;
        lseek(temp_file_fd,-sizeof(off_t),SEEK_END);
        read(temp_file_fd,&current_filesize,sizeof(off_t));
        // while(1){//每次一个off_t的大小进行读取临时文件
        //     int ret=read(temp_file_fd,&size,sizeof(off_t));
        //     if(0==ret){
        //         printf("read temp_file over\n");
        //         break;
        //     }
        //     current_filesize+=size;
        // } 
        send(netfb,&current_filesize,sizeof(current_filesize),MSG_NOSIGNAL);
        printf("=====current_filesize==%ld\n",current_filesize);
        // int temp_file_lseek_ret=lseek(temp_file_fd,current_filesize,SEEK_SET);//将临时文件的指针
        // printf("temp_file_lseek_ret=%d\n",temp_file_lseek_ret);
        //======================================================================  
        if(current_filesize==filesize){
            printf("该文件已存在,通知发送方不再发送，极速秒传，仅校验hash值\n");
            char flag[]="1";
            train.length=sizeof(flag);//发送标志位，让客户端不再发送
            strcpy(train.value,flag);
            send(netfb,&train.length,sizeof(train.length),0);
            send(netfb,train.value,train.length,0);
            //=================================================
            goto sha256_Hash;//goto sha1_Hash:校验现有文件hash值
        }else if(0<=current_filesize){
            char flag[]="0";
            train.length=sizeof(flag);//发送标志位，让服务端发送
            strcpy(train.value,flag);
            send(netfb,&train.length,sizeof(train.length),0);
            send(netfb,train.value,train.length,0);
        }
        //========================================================================
        int lseek_ret=lseek(file_fb,current_filesize,SEEK_SET);//设置文件指向,指到文件末尾
        printf("lseek_ret==%d\n",lseek_ret);
        //======================================================================
reload:
        struct timeval start, end;
        gettimeofday(&start, NULL);
        if(filesize<100*1024*1024){
            off_t total = 0;
            off_t last_size = 0;
            while (1)
            {
                // printf("%5.2lf%%\r", 100.0 * total / filesize);
                // fflush(stdout);
                if (total - last_size > 100000)
                {
                    show_progress_bar(total, filesize, &start);
                    last_size = total;
                }
                int ret = recv(netfb, &train.length, sizeof(train.length), MSG_WAITALL);
                if (train.length == 0)
                {
                    // 100%再打印一下
                    show_progress_bar(filesize, filesize, &start);
                    printf("\n"); // 完成后换行
                    printf("recv over\n");
                    break;
                }
                if (ret == 0)
                {
                    printf("发送方中断\n");
                    close(file_fb);
                    close(temp_file_fd);
                    return 0;
                }
                recv(netfb, train.value, train.length, MSG_WAITALL); // 如果是最后的车头为0的时，接收会阻塞吗
                write(file_fb, train.value, train.length);
                off_t one_size = train.length;
                write(temp_file_fd, &one_size, sizeof(off_t)); // 向临时文件写入每次传入的字节数
                total += train.length;
                // if(total==filesize){
                //     printf("recv over\n");
                //     break;
                // }
                bzero(train.value, train.length);
            }
            // printf("100.00%%\n");
            gettimeofday(&end, NULL);
            printf("耗时: %ld 秒\n", end.tv_sec - start.tv_sec);
        }else{
            char recv_data[1024 * 1024] = {0};
            int ftruncate_add_ret = ftruncate(file_fb, filesize);
            printf("ftruncate_add_ret=%d\n", ftruncate_add_ret);
            off_t last_size = current_filesize;
            long page_size = sysconf(_SC_PAGESIZE); // 获取系统页大小（通常 4KB）
            while (current_filesize < filesize) {
                off_t ret = recv(netfb, recv_data, sizeof(recv_data), 0);
                if (ret == 0) {
                    printf("发送方中断\n");
                    break;
                }
                // 计算对齐后的 offset（向下取整到页边界）
                off_t aligned_offset = (current_filesize / page_size) * page_size;
                // 计算映射后指针需要偏移的量（current_filesize - aligned_offset）
                size_t ptr_offset = current_filesize - aligned_offset;
                //要接收的剩余文件大小
                size_t remaining=filesize - aligned_offset;
                char *mapped = mmap(NULL, remaining, PROT_READ | PROT_WRITE, MAP_SHARED, file_fb, aligned_offset);
                if (mapped == MAP_FAILED) {
                    perror("mmap");
                    close(file_fb);
                    return -1;
                }

                // 调整指针，使其指向接收中断位置
                char *effective_ptr = mapped + ptr_offset;
                memcpy(effective_ptr, recv_data, ret);
                /* int w_ret= */
                /* printf("\n"); */
                /* printf("ret=%ld, w_ret=%d\n",ret,w_ret); */
                // 清理映射
                munmap(mapped, remaining);
                current_filesize += ret;
                write(temp_file_fd,&current_filesize,sizeof(current_filesize));//向临时文件写入每次传入的字节数
                /* sleep(1); */
                if (current_filesize - last_size > 100000)
                {
                    show_progress_bar(current_filesize, filesize, &start);
                    last_size = current_filesize;
                }
            }
            // 100%再打印一下
            show_progress_bar(current_filesize, filesize, &start);
            printf("\n"); // 完成后换行
            printf("接收完毕\n");
            // ftruncate(file_fb, current_filesize);
            gettimeofday(&end, NULL);
            printf("耗时: %ld 秒\n", end.tv_sec - start.tv_sec);
        }
sha256_Hash:  
        //判断文件是否损坏
        //计算hash值
        EVP_MD_CTX *ctx = EVP_MD_CTX_new();
        EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
        char buf[4096];
        /* int fb=open(,O_RDWR); */
        /* printf("fb==%d\n",fb); */
        lseek(file_fb, 0, SEEK_SET);
        while(1){
            bzero(buf,sizeof(buf));
            ssize_t ret=read(file_fb,buf,sizeof(buf));
            if(ret==0){
                printf("read over\n");
                break;
            }
            EVP_DigestUpdate(ctx, buf, ret);
        }
        unsigned char HASH_SHA[32];
        unsigned int encrypted_len = 0;
        EVP_DigestFinal_ex(ctx, HASH_SHA, &encrypted_len);
        char sha256str[65]={0};
        printf("file hash:");
        for (int i = 0; i < encrypted_len; i++)
        {
            sprintf(sha256str + i * 2, "%02x", HASH_SHA[i]);
        }
        sha256str[64] = '\0';
        printf("sha256str=%s\n",sha256str);

        if(strcmp(sha256str,recv_hash)==0){
            printf("校验hash相同\n");
            train.length=sizeof("0");
            strcpy(train.value,"0");
            send(netfb,&train.length,sizeof(train.length),0);
            send(netfb,train.value,train.length,0);
        }else{
            printf("校验hash不同\n");
            train.length=sizeof("1");
            strcpy(train.value,"1");
            send(netfb,&train.length,sizeof(train.length),0);
            send(netfb,train.value,train.length,0);
            lseek(file_fb,0,SEEK_SET);//设置文件指向,指到文件开始
            current_filesize=0;
            ftruncate(temp_file_fd,0);
            printf("重新接收文件\n");
            goto reload;
        }
       printf("recive file success\n");
    //    unlink(temp_file_name_path);
    }
    return 0;
}



int sendFile(char* fileName,int netfb, int log_fd){
    int file_fb=open(fileName,O_RDWR);//这个文件名是命令里切出来的
    // ERROR_CHECK(file_fb,-1,"open");
    if (file_fb == -1)
    {
        LOG_INFO(log_fd, LOG_ERROR, "open %s failed.", fileName);
        return -1;
    }
    train_t train;
    //  train.length=strlen(fileName);
    //  memcpy(train.value,fileName,strlen(fileName));
    //  send(netfb,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    //  send(netfb,train.value,train.length,MSG_NOSIGNAL);//客户端不send文件名
    struct stat statbuf;
    fstat(file_fb,&statbuf);
    off_t filesize=statbuf.st_size;
    train.length=sizeof(filesize);
    memcpy(train.value,&filesize,sizeof(filesize));
    send(netfb,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(netfb,train.value,train.length,MSG_NOSIGNAL);//发文件大小
    printf("filesize=%ld\n",filesize);
    // //计算hash值
    // SHA_CTX ctx;
    // SHA1_Init(&ctx);
    // char buf[4096];
    // int fb=open(fileName,O_RDWR);
    // printf("正在计算哈希值...\n");
    // while(1){
    //     bzero(buf,sizeof(buf));
    //     ssize_t  ret=read(fb,buf,sizeof(buf));
    //     if(ret==0){
    //         printf("read over\n");
    //         break;
    //     }
    //     SHA1_Update(&ctx,buf,ret);
    // }
    // unsigned char HASH_SHA[SHA_DIGEST_LENGTH];
    // SHA1_Final(HASH_SHA,&ctx);
    // char sha256str[SHA_DIGEST_LENGTH * 2 + 1]={0};
    // printf("file hash:");
    // for(int i=0;i<sizeof(HASH_SHA);i++){
    //     char temp[3]={0};
    //     sprintf(temp,"%02x",HASH_SHA[i]);
    //     strcat(sha256str,temp);
    // }
    // printf("sha1str=%s\n",sha256str);

    //计算hash值
    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
    EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
    char buf[4096];
    int fb=open(fileName,O_RDWR);
    printf("正在计算哈希值...\n");
    while(1){
        bzero(buf,sizeof(buf));
        ssize_t  ret=read(fb,buf,sizeof(buf));
        if(ret==0){
            printf("read over\n");
            break;
        }
        EVP_DigestUpdate(ctx, buf, ret);
    }
    unsigned char HASH_SHA[32];
    unsigned int encrypted_len = 0;
    EVP_DigestFinal_ex(ctx, HASH_SHA, &encrypted_len);
    char sha256str[65]={0};
    printf("file hash:");
    for (int i = 0; i < encrypted_len; i++)
    {
        sprintf(sha256str + i * 2, "%02x", HASH_SHA[i]);
    }
    sha256str[64] = '\0';
    printf("sha256str=%s\n",sha256str);
    //send hash
    train.length=sizeof(sha256str);
    send(netfb,&train.length,sizeof(train.length),0);
    send(netfb,sha256str,train.length,0);
    //接收使用对应临时文件算出的已经传送的字节数量
    off_t current_send_over_length=-1;
    recv(netfb,&current_send_over_length,sizeof(current_send_over_length),MSG_WAITALL);
    printf("current_send_over_length=%ld\n",current_send_over_length);
    //recv 接收方标识位，判断是否极速秒传
    recv(netfb,&train.length,sizeof(train.length),MSG_WAITALL);
    bzero(train.value,sizeof(train.value));
    recv(netfb,train.value,train.length,MSG_WAITALL);
    //===========================================================================
    if(strcmp(train.value,"1")==0){
        printf("不再发送，极速秒传\n");
        goto sha256;
    }else{
        printf("开始发送文件\n");
    }
    //==============================================================================


    int lseek_ret=lseek(file_fb,current_send_over_length,SEEK_SET);//设置文件指向
    printf("lseek_ret==%d\n",lseek_ret);
re_send:
    if(filesize<100*1024*1024){
        struct timeval start, end;
        gettimeofday(&start, NULL);
        off_t total = 0, last_size = 0;
        while(1){//发文件内容
            char read_data[1024]={0};
            // int ret=read(file_fb,read_data,sizeof(read_data));//这里不用小火车，直接全部发送
            // if(ret==0){
            //     printf("send small file over\n");
            //     break;
            // }
            // send(netfb,&ret, sizeof(ret), MSG_NOSIGNAL);
            // send(netfb,read_data,ret,MSG_NOSIGNAL);
            int ret = read(file_fb, read_data, sizeof(read_data));
            train.length = ret;
            memcpy(train.value, read_data, train.length);
            total += ret;
            send(netfb, &train.length, sizeof(train.length), MSG_NOSIGNAL);
            if (total - last_size > 100000)
            {
                show_progress_bar(total, filesize, &start);
                last_size = total;
            }
            if(ret == 0)
            {
                // 100%再打印一下
                show_progress_bar(filesize, filesize, &start);
                printf("\n"); // 完成后换行
                printf("send small file over\n");
                gettimeofday(&end, NULL);
                printf("耗时: %ld 秒\n", end.tv_sec - start.tv_sec);
                break;
            }
            send(netfb, train.value, train.length, MSG_NOSIGNAL);
            // usleep(10); // 发慢一点，debug用            
        }
    }else{
        struct timeval start, end;
        gettimeofday(&start, NULL);
        off_t offset = current_send_over_length;
        off_t CHUNK_SIZE = 1024 * 1024; // 1MB，每次发送<=1MB的数据
        long page_size = sysconf(_SC_PAGESIZE); // 获取系统页大小（通常 4KB）
        off_t last_size = offset;
        while (offset < filesize) {
            size_t remaining = filesize - offset;
            size_t current_chunk_size = remaining < CHUNK_SIZE ? remaining : CHUNK_SIZE;

            // 计算对齐后的 offset（向下取整到页边界）
            off_t aligned_offset = (offset / page_size) * page_size;
            // 计算映射后指针需要偏移的量（offset - aligned_offset）,
            size_t ptr_offset = offset - aligned_offset;//ptr_offset > 0
                                                        // 实际映射的长度 = 当前块大小 + 额外对齐偏移（避免越界）
            size_t mmap_length = current_chunk_size + ptr_offset;

            // 映射对齐后的区域
            char *mapped = mmap(NULL, mmap_length, PROT_READ, MAP_SHARED, file_fb, aligned_offset);
            if (mapped == MAP_FAILED) {
                perror("mmap failed");
                close(file_fb);
                return -1;
            }

         // 调整指针，使其指向文件要开始发送的位置
            char *effective_ptr = mapped + ptr_offset;
            // 实际发送的数据大小仍然是 current_chunk_size
            size_t sent = 0;
            while (sent < current_chunk_size) {
                ssize_t bytes_sent = send(netfb, effective_ptr + sent, current_chunk_size - sent, MSG_NOSIGNAL);
                if (bytes_sent == -1) {
                    perror("send failed");
                    munmap(mapped, mmap_length);
                    close(file_fb);
                    return -1;
                }
                sent += bytes_sent;
            }

            // 清理映射
            munmap(mapped, mmap_length);
            offset += current_chunk_size;
            if (offset - last_size > 1000000)
            {
                show_progress_bar(offset, filesize, &start);
                last_size = offset;
            }
        }
        // 100%再打印一下
        show_progress_bar(filesize, filesize, &start);
        printf("\n"); // 完成后换行
        printf("send big file over\n");
        close(file_fb);
        gettimeofday(&end, NULL);
        printf("耗时: %ld 秒\n", end.tv_sec - start.tv_sec);
    }
// sha1:
sha256:
    //recv 接收方标识位，判断是否重传
     printf("文件校验中...\n");
     recv(netfb,&train.length,sizeof(train.length),MSG_WAITALL);
     bzero(train.value,sizeof(train.value));
     recv(netfb,train.value,train.length,MSG_WAITALL);
     if(strcmp(train.value,"1")==0){
         printf("文件损坏,重新传输\n");
         lseek(file_fb,0,SEEK_SET);//设置指向到文件开始
         current_send_over_length=0;
         goto re_send;
     }else{
         printf("文件校验完毕，文件无损坏\n");
     }
    return 0;
}